﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Zack.EFCore.Batch.Internal;

namespace EFCoreDemo
{
    /// <summary>
    /// BaseRepository
    /// </summary>
    public abstract class BaseRepository<TEntity, TKey, TDbContext> : QueryRepository<TEntity, TKey, TDbContext>, IRepository<TEntity, TKey, TDbContext> where TDbContext : DbContext where TEntity : IEntity<TKey>
    {
        /// <summary>
        /// ctor
        /// </summary>
        public BaseRepository(TDbContext context)
            : base(context)
        {
            DbContext = context;
        }

        /// <summary>
        /// DbContext
        /// </summary>
        public TDbContext DbContext { get; }

        /// <summary>
        /// 新增
        /// </summary>
        public async Task<TEntity> AddAsync(TEntity entity)
        {
            var result = await DbContext.AddAsync(entity);
            await SaveChangeAsync();
            return result.Entity;
        }

        /// <summary>
        /// 批量新增
        /// </summary>
        public async Task<bool> BulkAddAsync(IList<TEntity> entityList)
        {
            await DbContext.AddRangeAsync(entityList);
            await SaveChangeAsync();
            return true;
        }

        /// <summary>
        /// 快速批量新增，未跟踪实体
        /// </summary>
        public async virtual Task<bool> FastBulkAddAsync(IList<TEntity> entityList)
        {
            var dbTran = DbContext.Database?.CurrentTransaction == null ? null : DbContext.Database.CurrentTransaction.GetDbTransaction();
            await DbContext.BulkInsertAsync(entityList, (MySqlConnector.MySqlTransaction)dbTran);
            return true;
        }

        /// <summary>
        /// 删除
        /// </summary>
        public async Task<bool> DeleteAsync(TEntity entity)
        {
            DbContext.Remove(entity);
            await SaveChangeAsync();
            return await Task.FromResult(true);
        }

        /// <summary>
        /// 删除，可跟踪/不跟踪
        /// </summary>
        /// <param name="id">主键id</param>
        public abstract Task<bool> DeleteAsync(TKey id);

        /// <summary>
        /// 删除，未跟踪
        /// </summary>
        public async Task<bool> DeleteAsync(Expression<Func<TEntity, bool>> condition)
        {
            var result = await DbContext.DeleteRangeAsync(condition) >= 0;
            return result;
        }

        /// <summary>
        /// 更新
        /// </summary>
        public async Task<TEntity> UpdateAsync(TEntity entity)
        {
            var result = DbContext.Update(entity);
            await SaveChangeAsync();
            return await Task.FromResult(result.Entity);
        }

        /// <summary>
        /// 部分字段更新执行体（未跟踪），返回执行类
        /// set -> 字段更新
        /// where -> 条件
        /// execute ->最终执行
        /// </summary>
        /// <returns></returns>
        public async Task<BatchUpdateBuilder<TEntity>> UpdatePartialAsync()
        {
            return await Task.FromResult(DbContext.BatchUpdate<TEntity>());
        }

        #region private methods
        /// <summary>
        /// 判断是否开启事务，未开启直接提交数据库
        /// </summary>
        private async Task SaveChangeAsync()
        {
            if (DbContext.Database?.CurrentTransaction == null)
            {
                await DbContext.SaveChangesAsync();
            }
        }
        #endregion
    }

    public abstract class QueryRepository<TEntity, TKey, TDbContext> : IQueryable<TEntity>, IAsyncEnumerable<TEntity> where TDbContext : DbContext where TEntity : IEntity<TKey>
    {
        private readonly TDbContext _context;

        public QueryRepository(TDbContext context)
        {
            _context = context;
        }

        public Type ElementType => GetQueryable().ElementType;

        public Expression Expression => GetQueryable().Expression;

        public IQueryProvider Provider => GetQueryable().Provider;

        public IAsyncEnumerator<TEntity> GetAsyncEnumerator(CancellationToken cancellationToken = default)
        {
            return GetQueryable().AsAsyncEnumerable().GetAsyncEnumerator();
        }

        public IEnumerator<TEntity> GetEnumerator()
        {
            return GetQueryable().GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #region private methods

        private IQueryable<TEntity> GetQueryable()
        {
            return _context.Set<TEntity>().AsQueryable<TEntity>();
        }

        #endregion
    }

    /// <summary>
    /// UlongBaseRepository,主键ulong
    /// </summary>
    public abstract class UlongBaseRepository<TEntity, TDbContext> : BaseRepository<TEntity, ulong, TDbContext> where TEntity : IEntity<ulong> where TDbContext : DbContext
    {
        protected UlongBaseRepository(TDbContext context)
            : base(context)
        {
        }

        /// <summary>
        /// 删除，未跟踪
        /// </summary>
        /// <param name="id">主键id</param>
        public async override Task<bool> DeleteAsync(ulong id)
        {
            var result = await DbContext.DeleteRangeAsync<TEntity>(entity => entity.Id == id) >= 0;
            return result;
        }
    }

    /// <summary>
    /// StringBaseRepository,主键string
    /// </summary>
    public abstract class StringBaseRepository<TEntity, TDbContext> : BaseRepository<TEntity, string, TDbContext> where TEntity : IEntity<string> where TDbContext : DbContext
    {
        protected StringBaseRepository(TDbContext context)
            : base(context)
        {
        }

        /// <summary>
        /// 删除，未跟踪
        /// </summary>
        /// <param name="id">主键id</param>
        public async override Task<bool> DeleteAsync(string id)
        {
            var result = await DbContext.DeleteRangeAsync<TEntity>(entity => entity.Id == id) >= 0;
            return result;
        }
    }
}
